package com.kwdb.importtool.core;

import com.kwdb.importtool.config.DatabaseConfig;
import com.kwdb.importtool.config.MigrationConfig;
import com.kwdb.importtool.model.MigrationResult;
import com.kwdb.importtool.model.SQLStatement;
import com.kwdb.importtool.util.DBConnection;
import com.kwdb.importtool.util.FileUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * KWDB迁移执行器
 * 负责协调整个迁移过程
 */
@Data
@Slf4j
public class KWDBMigrator {
    private static final Logger logger = LoggerFactory.getLogger(KWDBMigrator.class);

    private DatabaseConfig dbConfig;
    private MigrationConfig migrationConfig;
    private SQLParser sqlParser;
    private SQLConverter sqlConverter;
    private DataValidator dataValidator;

    private Connection kwdbConnection;
    private Connection mysqlConnection;

    // 迁移状态
    private MigrationResult migrationResult;
    private AtomicInteger currentStep;
    private AtomicLong processedStatements;
    private AtomicLong successfulStatements;
    private AtomicLong failedStatements;

    // 线程池
    private ExecutorService executorService;
    private List<Future<StatementResult>> futures;

    // 回调接口
    private MigrationProgressListener progressListener;

    public KWDBMigrator(DatabaseConfig dbConfig, MigrationConfig migrationConfig) {
        this.dbConfig = dbConfig;
        this.migrationConfig = migrationConfig;
        this.sqlParser = new SQLParser();
        this.sqlConverter = new SQLConverter();
        this.dataValidator = new DataValidator(dbConfig, migrationConfig);

        this.migrationResult = new MigrationResult();
        this.currentStep = new AtomicInteger(0);
        this.processedStatements = new AtomicLong(0);
        this.successfulStatements = new AtomicLong(0);
        this.failedStatements = new AtomicLong(0);

        // 初始化线程池
        int threadCount = migrationConfig.getMaxThreads();
        this.executorService = Executors.newFixedThreadPool(threadCount);
        this.futures = new ArrayList<>();
    }

    /**
     * 执行完整迁移过程
     */
    /**
     * 执行完整迁移过程
     */
    public MigrationResult executeMigration() {
        logger.info("Starting MySQL to KWDB migration...");
        migrationResult.setStartTime(new Date());

        try {
            // 1. 首先执行备份（如果启用了备份选项）
            if (migrationConfig.isBackupOriginal()) {
                notifyProgress("Backing up original files...", 5);
                performBackup();
            }

            // 2. 建立数据库连接
            connectToDatabases();

            // 3. 解析SQL文件
            notifyProgress("SQL file...", 10);
            List<SQLStatement> sqlStatements = parseSQLFile();
            if (sqlStatements == null || sqlStatements.isEmpty()) {
                throw new MigrationException("No valid SQL statements found in the file");
            }

            // 转换SQL语法
            notifyProgress("Convert SQL syntax...", 20);
            List<SQLStatement> convertedStatements = convertSQLStatements(sqlStatements);

/*            List<SQLStatement> effectiveStatements = convertedStatements.stream()
                    .filter(stmt -> !stmt.getConvertedSQL().isEmpty())
                    .collect(Collectors.toList());*/

            // 分组SQL语句
            Map<StatementType, List<SQLStatement>> groupedStatements = groupStatementsByType(convertedStatements);

            // 按顺序执行迁移
            executeMigrationByPhase(groupedStatements);

            // 迁移成功
            migrationResult.setSuccess(true);
            migrationResult.setMessage("Migration completed successfully");

            // 设置最终的统计信息
            migrationResult.setProcessedStatements((int) processedStatements.get());
            migrationResult.setSuccessfulStatements((int) successfulStatements.get());
            migrationResult.setFailedStatements((int) failedStatements.get());
            migrationResult.setTotalStatements((int) processedStatements.get());

            notifyProgress("The migration is complete！", 100);

        } catch (MigrationException e) {
            handleMigrationError("Migration failed", e);
        } catch (Exception e) {
            handleMigrationError("Unexpected error during migration", e);
        } finally {
            cleanup();
        }

        migrationResult.setEndTime(new Date());
        logMigrationSummary();

        return migrationResult;
    }

    /**
     * 执行备份操作
     */
    private void performBackup() {
        try {
            String sqlFilePath = migrationConfig.getSqlFilePath();

            if (sqlFilePath == null || sqlFilePath.trim().isEmpty()) {
                logger.warn("SQL file path is empty, skipping backup");
                return;
            }

            File sqlFile = new File(sqlFilePath);
            if (!sqlFile.exists()) {
                logger.warn("SQL file does not exist: {}, skipping backup", sqlFilePath);
                return;
            }

            // 确定备份目录
            File backupDir;
            String outputDir = migrationConfig.getOutputDir();
            if (outputDir != null && !outputDir.trim().isEmpty()) {
                backupDir = new File(outputDir, "backups");
            } else {
                backupDir = new File(sqlFile.getParentFile(), "backups");
            }

            // 使用FileUtils的备份方法
            File backupFile = FileUtils.backupFile(sqlFile, backupDir);


            logger.info("Backup completed successfully: {} -> {}", sqlFile.getPath(), backupFile.getPath());

        } catch (Exception e) {
            // 备份失败不应该阻止迁移继续，只记录警告
            String errorMsg = "Backup failed: " + e.getMessage();
            logger.warn(errorMsg, e);
            migrationResult.addWarning(errorMsg);
        }
    }

    /**
     * 按阶段执行迁移
     */
    private void executeMigrationByPhase(Map<StatementType, List<SQLStatement>> groupedStatements) {
        // 阶段0: 删除操作优先执行
        executeStatementsIfEnabled(groupedStatements.get(StatementType.DROP), "Drop objects", true);

        // 阶段1: 创建数据库
        executeStatementsIfEnabled(groupedStatements.get(StatementType.CREATE_DATABASE),
                "Create database", migrationConfig.isCreateDatabase());

        // 阶段2: 创建表结构
        executeStatementsIfEnabled(groupedStatements.get(StatementType.CREATE_TABLE),
                "Create tables", migrationConfig.isCreateTables());

        // 阶段3: 导入数据
        executeStatementsIfEnabled(groupedStatements.get(StatementType.INSERT),
                "Import data", migrationConfig.isImportData());

        // 阶段4: 创建索引
        executeStatementsIfEnabled(groupedStatements.get(StatementType.CREATE_INDEX),
                "Create indexes", migrationConfig.isCreateIndexes());

        // 阶段5: 创建序列
        executeStatementsIfEnabled(groupedStatements.get(StatementType.CREATE_SEQUENCE),
                "Create sequences", migrationConfig.isCreateSequences());

        // 阶段6: 执行注释语句
        executeStatementsIfEnabled(groupedStatements.get(StatementType.COMMENT),
                "Add comments", true);

        // 阶段7: 执行ALTER语句
        executeStatementsIfEnabled(groupedStatements.get(StatementType.ALTER),
                "Alter tables", true);

        // 阶段8: 执行其他未分类语句
        executeOtherStatements(groupedStatements.get(StatementType.OTHER));

        // 等待所有异步任务完成
        waitForAsyncTasks();
    }

    // 新增辅助方法：有条件执行语句列表
    private void executeStatementsIfEnabled(List<SQLStatement> statements, String operation, boolean enabled) {
        if (enabled && statements != null && !statements.isEmpty()) {
            notifyProgress(operation + "...", getProgressForPhase(operation));
            logger.info("Executing {} {} statements", statements.size(), operation.toLowerCase());

            for (SQLStatement statement : statements) {
                executeStatement(statement, operation);
            }
        }
    }

    // 新增方法：处理其他类型语句
    private void executeOtherStatements(List<SQLStatement> otherStatements) {
        if (otherStatements == null || otherStatements.isEmpty()) {
            return;
        }

        notifyProgress("Executing other statements...", 85);
        logger.info("Executing {} other statements", otherStatements.size());

        // 先尝试分类执行
        Map<StatementType, List<SQLStatement>> classified = classifyOtherStatements(otherStatements);

        // 执行分类后的语句
        executeStatementsIfEnabled(classified.get(StatementType.CREATE_INDEX), "Create indexes from OTHER", true);
        executeStatementsIfEnabled(classified.get(StatementType.ALTER), "Alter tables from OTHER", true);
        executeStatementsIfEnabled(classified.get(StatementType.COMMENT), "Comments from OTHER", true);

        // 执行剩余未分类语句
        List<SQLStatement> remaining = classified.get(StatementType.OTHER);
        if (remaining != null && !remaining.isEmpty()) {
            logger.warn("Executing {} unclassified statements", remaining.size());
            for (SQLStatement statement : remaining) {
                executeStatement(statement, "Unclassified statement");
            }
        }
    }

    //对其他语句进行二次分类
    private Map<StatementType, List<SQLStatement>> classifyOtherStatements(List<SQLStatement> otherStatements) {
        Map<StatementType, List<SQLStatement>> classified = new EnumMap<>(StatementType.class);
        for (StatementType type : StatementType.values()) {
            classified.put(type, new ArrayList<>());
        }

        for (SQLStatement statement : otherStatements) {
            String sql = statement.getOriginalSQL().toUpperCase();
            StatementType type = StatementType.OTHER;

            if (sql.contains("CREATE INDEX") || sql.contains("CREATE UNIQUE INDEX")) {
                type = StatementType.CREATE_INDEX;
            } else if (sql.contains("COMMENT ON")) {
                type = StatementType.COMMENT;
            } else if (sql.contains("ALTER TABLE")) {
                type = StatementType.ALTER;
            }

            classified.get(type).add(statement);
        }

        return classified;
    }

    // 获取各阶段的进度百分比
    private int getProgressForPhase(String phase) {
        switch (phase) {
            case "Drop objects": return 30;
            case "Create database": return 35;
            case "Create tables": return 40;
            case "Import data": return 50;
            case "Create indexes": return 70;
            case "Create sequences": return 75;
            case "Add comments": return 80;
            case "Alter tables": return 85;
            default: return 90;
        }
    }


    /**
     * 解析SQL文件
     */
    private List<SQLStatement> parseSQLFile() throws MigrationException {
        try {
            List<SQLStatement> statements = sqlParser.parseFile(migrationConfig.getSqlFilePath());
//            migrationResult.setTotalStatements(statements.size());
            migrationResult.setSourceStatementCount(statements.size());
            migrationResult.setSourceFile(migrationConfig.getSqlFilePath());
            logger.info("Parsed {} SQL statements from file: {}", statements.size(), migrationConfig.getSqlFilePath());
            return statements;
        } catch (Exception e) {
            throw new MigrationException("Failed to parse SQL file: " + e.getMessage(), e);
        }
    }

    /**
     * 转换SQL语句
     */
    private List<SQLStatement> convertSQLStatements(List<SQLStatement> originalStatements) {
        List<SQLStatement> converted = new ArrayList<>();

        for (SQLStatement statement : originalStatements) {
            try {
                SQLStatement convertedStatement = sqlConverter.convert(statement);
                converted.add(convertedStatement);

                // 如果是CREATE TABLE语句，额外生成注释和索引
                if (statement.getStatementType() == SQLStatement.StatementType.CREATE_TABLE) {
                    // 生成列注释语句
                    List<String> commentStatements = sqlConverter.generateColumnComments(statement.getOriginalSQL());
                    for (String commentSQL : commentStatements) {
                        SQLStatement commentStmt = new SQLStatement();
                        commentStmt.setOriginalSQL(commentSQL);
                        commentStmt.setConvertedSQL(commentSQL);
                        commentStmt.setStatementType(SQLStatement.StatementType.COMMENT);
                        converted.add(commentStmt);
                    }

                    // 生成索引语句（包括FULLTEXT索引转换）
                    List<String> indexStatements = sqlConverter.generateIndexStatements(statement.getOriginalSQL());
                    for (String indexSQL : indexStatements) {
                        SQLStatement indexStmt = new SQLStatement();
                        indexStmt.setOriginalSQL(indexSQL);
                        indexStmt.setConvertedSQL(indexSQL);
                        indexStmt.setStatementType(SQLStatement.StatementType.CREATE_INDEX);
                        converted.add(indexStmt);
                    }
                }

            } catch (Exception e) {
                logger.warn("Failed to convert SQL statement: {}", statement.getOriginalSQL(), e);
                if (migrationConfig.isSkipErrors()) {
                    converted.add(statement); // 使用原始语句
                } else {
                    throw new MigrationException("SQL conversion failed for: " + statement.getOriginalSQL(), e);
                }
            }
        }

        return converted;
    }

    /**
     * 执行数据库删除
     */
    private void executeDatabaseDrop(List<SQLStatement> databaseStatements) {
        notifyProgress("删除数据库中...", 30);
        logger.info("Executing {} Drop the database", databaseStatements.size());

        for (SQLStatement statement : databaseStatements) {
            executeStatement(statement, "Database creation");
        }
    }
    /**
     * 执行数据库创建
     */
    private void executeDatabaseCreation(List<SQLStatement> databaseStatements) {
        notifyProgress("创建数据库中...", 30);
        logger.info("Executing {} database creation statements", databaseStatements.size());

        for (SQLStatement statement : databaseStatements) {
            executeStatement(statement, "Database creation");
        }
    }

    /**
     * 执行表创建
     */
    private void executeTableCreation(List<SQLStatement> tableStatements) {
        notifyProgress("创建表结构中...", 40);
        logger.info("Executing {} table creation statements", tableStatements.size());

        for (SQLStatement statement : tableStatements) {
            executeStatement(statement, "Table creation");
        }
    }

    /**
     * 执行数据导入
     */
    private void executeDataImport(List<SQLStatement> insertStatements) {
        notifyProgress("导入数据中...", 50);
        logger.info("Executing {} data import statements", insertStatements.size());

        int batchSize = migrationConfig.getBatchSize();
        List<SQLStatement> batch = new ArrayList<>();

        for (SQLStatement statement : insertStatements) {
            batch.add(statement);

            if (batch.size() >= batchSize) {
                executeBatchInsert(batch);
                batch.clear();
            }
        }

        // 执行剩余批次
        if (!batch.isEmpty()) {
            executeBatchInsert(batch);
        }
    }

    /**
     * 执行批量插入
     */
    private void executeBatchInsert(List<SQLStatement> batch) {
        if (migrationConfig.isParallelMigration()) {
            // 异步执行
            futures.add(executorService.submit(() -> executeBatchSync(batch)));
        } else {
            // 同步执行
            executeBatchSync(batch);
        }
    }

    /**
     * 同步执行批次
     */
    private StatementResult executeBatchSync(List<SQLStatement> batch) {
        StatementResult result = new StatementResult();

        try {
            kwdbConnection.setAutoCommit(false);

            for (SQLStatement statement : batch) {
                try (PreparedStatement pstmt = kwdbConnection.prepareStatement(statement.getConvertedSQL())) {
                    pstmt.executeUpdate();
                    result.incrementSuccessCount();
                } catch (SQLException e) {
                    if (migrationConfig.isSkipErrors()) {
                        logger.warn("Failed to execute statement, skipping: {}", statement.getConvertedSQL(), e);
                        result.incrementErrorCount();
                    } else {
                        throw e;
                    }
                }
            }

            kwdbConnection.commit();

        } catch (SQLException e) {
            try {
                kwdbConnection.rollback();
            } catch (SQLException rollbackEx) {
                logger.error("Failed to rollback transaction", rollbackEx);
            }
            result.setError(e.getMessage());
        } finally {
            try {
                kwdbConnection.setAutoCommit(true);
            } catch (SQLException e) {
                logger.error("Failed to set auto-commit", e);
            }
        }

        // 更新计数器
        processedStatements.addAndGet(batch.size());
        successfulStatements.addAndGet(result.getSuccessCount());
        failedStatements.addAndGet(result.getErrorCount());

        updateProgress();

        return result;
    }

    /**
     * 执行索引创建
     */
    private void executeIndexCreation(List<SQLStatement> indexStatements) {
        notifyProgress("创建索引中...", 70);
        logger.info("Executing {} index creation statements", indexStatements.size());

        for (SQLStatement statement : indexStatements) {
            executeStatement(statement, "Index creation");
        }
    }

    /**
     * 执行序列创建
     */
    private void executeSequenceCreation(List<SQLStatement> sequenceStatements) {
        notifyProgress("创建序列中...", 80);
        logger.info("Executing {} sequence creation statements", sequenceStatements.size());

        for (SQLStatement statement : sequenceStatements) {
            executeStatement(statement, "Sequence creation");
        }
    }

    /**
     * 执行单个SQL语句
     */
    private void executeStatement(SQLStatement statement, String operation) {
        if (statement == null) {
            return;
        }

        try {
            long startTime = System.currentTimeMillis();

            try (Statement stmt = kwdbConnection.createStatement()) {
                stmt.setQueryTimeout(migrationConfig.getQueryTimeout());
                stmt.execute(statement.getConvertedSQL());

                long duration = System.currentTimeMillis() - startTime;
                logger.info("Successfully executed {} statement in {}ms: {}",
                        operation, duration, statement.getConvertedSQL());
                logger.debug("Successfully executed {} statement in {}ms: {}",
                        operation, duration, statement.getConvertedSQL());

                successfulStatements.incrementAndGet();
            }

        } catch (SQLException e) {
            failedStatements.incrementAndGet();
            String errorMsg = String.format("Failed to execute %s statement: %s", operation, e.getMessage());

            logger.info("failed executed {} ，errorMsg {}，sql: {}",
                    operation,errorMsg,statement.getConvertedSQL());
            logger.info("failed sql: {}",
                    statement.getConvertedSQL());
            if (migrationConfig.isSkipErrors()) {
                logger.warn(errorMsg);
                migrationResult.addWarning(errorMsg);
            } else {
                throw new MigrationException(errorMsg, e);
            }
        } finally {
            processedStatements.incrementAndGet();
            updateProgress();
        }
    }

    /**
     * 等待异步任务完成
     */
    private void waitForAsyncTasks() {
        if (futures.isEmpty()) {
            return;
        }

        for (Future<StatementResult> future : futures) {
            try {
                StatementResult result = future.get(10, TimeUnit.MINUTES);
                // 处理结果
            } catch (TimeoutException e) {
                logger.error("Async task timed out", e);
                future.cancel(true);
            } catch (Exception e) {
                logger.error("Async task failed", e);
            }
        }
    }

    /**
     * 验证迁移结果
     */
    private void validateMigration() {
        try {
            DataValidator.ValidationSummary summary = dataValidator.validateMigration();
            migrationResult.setValidationSummary(summary);

            if (!summary.isOverallSuccess()) {
                migrationResult.addWarning("Data validation completed with issues");
                logger.warn("Data validation completed with {} errors", summary.getErrorMessages().size());
            } else {
                logger.info("Data validation completed successfully");
            }

        } catch (Exception e) {
            logger.error("Data validation failed", e);
            migrationResult.addWarning("Data validation failed: " + e.getMessage());
        }
    }

    /**
     * 分组SQL语句
     */
    private Map<StatementType, List<SQLStatement>> groupStatementsByType(List<SQLStatement> statements) {
        Map<StatementType, List<SQLStatement>> grouped = new EnumMap<>(StatementType.class);

        for (StatementType type : StatementType.values()) {
            grouped.put(type, new ArrayList<>());
        }

        for (SQLStatement statement : statements) {
            StatementType type = determineStatementType(statement);
            grouped.get(type).add(statement);
        }

        return grouped;
    }

    /**
     * 确定语句类型
     */
    private StatementType determineStatementType(SQLStatement statement) {
        String sql = statement.getOriginalSQL().toUpperCase();

        // 更精确的类型识别
        if (sql.startsWith("CREATE DATABASE")) {
            return StatementType.CREATE_DATABASE;
        } else if (sql.startsWith("CREATE TABLE")) {
            return StatementType.CREATE_TABLE;
        } else if (sql.startsWith("INSERT INTO")) {
            return StatementType.INSERT;
        } else if (sql.startsWith("CREATE INDEX") || sql.startsWith("CREATE UNIQUE INDEX")) {
            return StatementType.CREATE_INDEX;
        } else if (sql.startsWith("COMMENT ON")) {
            return StatementType.COMMENT;
        } else if (sql.startsWith("CREATE SEQUENCE")) {
            return StatementType.CREATE_SEQUENCE;
        } else if (sql.startsWith("DROP TABLE")) {
            return StatementType.DROP;
        } else if (sql.startsWith("ALTER TABLE")) {
            return StatementType.ALTER;
        } else {
            return StatementType.OTHER;
        }
    }

    /**
     * 建立数据库连接
     */
    private void connectToDatabases() throws SQLException {
        logger.info("Connecting to databases...");

        kwdbConnection = DBConnection.getKWDBConnection(dbConfig);
        logger.info("Connected to KWDB: {}", dbConfig.getKwdbUrl());

        // MySQL连接主要用于验证，不是必须的
        if (dbConfig.isMysqlConfigValid() && migrationConfig.shouldValidateMigration()) {
            mysqlConnection = DBConnection.getMySQLConnection(dbConfig);
            logger.info("Connected to MySQL: {}", dbConfig.getMysqlUrl());
        }
    }

    /**
     * 清理资源
     */
    private void cleanup() {
        DBConnection.closeConnection(kwdbConnection);
        DBConnection.closeConnection(mysqlConnection);

        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 处理迁移错误
     */
    private void handleMigrationError(String message, Exception e) {
        logger.error(message, e);
        migrationResult.setSuccess(false);
        migrationResult.setMessage(message + ": " + e.getMessage());
        migrationResult.addError(e.getMessage());

        // 设置最终的统计信息
        migrationResult.setProcessedStatements((int) processedStatements.get());
        migrationResult.setSuccessfulStatements((int) successfulStatements.get());
        migrationResult.setFailedStatements((int) failedStatements.get());

        // 设置失败时的进度为当前实际进度
        migrationResult.setProgress(Math.min(90, (int) ((processedStatements.get() * 90) / migrationResult.getTotalStatements())));

        if (e instanceof MigrationException) {
            migrationResult.addError(((MigrationException) e).getDetailedMessage());
        }
    }

    /**
     * 更新进度
     */
    private void updateProgress() {
        if (migrationResult.getTotalStatements() > 0) {
            int progress = (int) ((processedStatements.get() * 40) / migrationResult.getTotalStatements()) + 50;
            notifyProgress("执行SQL语句中...", Math.min(progress, 90));
        }
    }

    /**
     * 通知进度更新
     */
    private void notifyProgress(String message, int progress) {
        migrationResult.setCurrentStep(message);
        migrationResult.setProgress(progress);

        if (progressListener != null) {
            progressListener.onProgressUpdate(message, progress);
        }
    }

    /**
     * 记录迁移摘要
     */
    private void logMigrationSummary() {
        logger.info("=== Migration Summary ===");
        logger.info("Total statements processed: {}", processedStatements.get());
        logger.info("Successful statements: {}", successfulStatements.get());
        logger.info("Failed statements: {}", failedStatements.get());
        logger.info("Success rate: {:.2f}%",
                processedStatements.get() > 0 ?
                        (successfulStatements.get() * 100.0 / processedStatements.get()) : 0);
        logger.info("Migration status: {}", migrationResult.isSuccess() ? "SUCCESS" : "FAILED");
    }

    /**
     * 语句类型枚举
     */
    public enum StatementType {
        CREATE_DATABASE, CREATE_TABLE, INSERT, CREATE_INDEX, CREATE_SEQUENCE, DROP, ALTER, OTHER,COMMENT
    }

    /**
     * 语句执行结果
     */
    @Data
    public static class StatementResult {
        private int successCount = 0;
        private int errorCount = 0;
        private String error;

        public void incrementSuccessCount() {
            successCount++;
        }

        public void incrementErrorCount() {
            errorCount++;
        }
    }

    /**
     * 迁移进度监听器接口
     */
    public interface MigrationProgressListener {
        void onProgressUpdate(String message, int progress);
    }

    /**
     * 迁移异常
     */
    public static class MigrationException extends RuntimeException {
        public MigrationException(String message) {
            super(message);
        }

        public MigrationException(String message, Throwable cause) {
            super(message, cause);
        }

        public String getDetailedMessage() {
            return getMessage() + (getCause() != null ? " - Caused by: " + getCause().getMessage() : "");
        }
    }
}